//
//  main.c
//  串口工具c实现
//
//  Created by MT-SW-003 on 2021/4/12.
//  Copyright © 2021 MT-SW-003. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#define  MCUUARTPORT "/dev/tty.usbserial-Fixture"


//写入数据
ssize_t writedata(int fd,char *sendBUff){
    printf("write data: %s\n",sendBUff);
    size_t len;
    ssize_t w_ok;
    strcat(sendBUff,"\r\n\0");
    len=strlen(sendBUff);
    w_ok =write(fd, sendBUff, len);
    printf("w_ok:%zd\n",w_ok);
    if(w_ok<0) {
        printf("write failed:w_len:%zd\n",w_ok);
    }
    else{
        printf("write fd: %d,str: %s len: %zd\n",fd,sendBUff,len);
    }
    return w_ok;
}

//读取数据
ssize_t readData(int fd,char *readBuff,size_t r_len){
    ssize_t r_ok;
    r_ok= read(fd,readBuff,r_len);
    printf("r_ok %zd\n",r_ok);
    return  r_ok;
}
int main(void) {
    
    int fd;
   
    /* ====================打开串口设备==================== */
    printf(" init dev start\n");
    //打开设备/dev/path
    fd = open(MCUUARTPORT, O_RDWR | O_NDELAY | O_NOCTTY|O_NONBLOCK);
    if (-1 == fd) {
        printf("open serial port %s fail %d\n", MCUUARTPORT, fd);
        return fd;
    }
    printf("fd:%d\n",fd);
    fcntl(fd, F_SETFL, 0);//设置文件状态标志值为０,阻塞模式
    printf("open device success\n");
    
    /* ====================设置串口属性==================== */
  
    printf("set baudrate\n");
    struct termios options; //串口属于终端设备，其接口属性用termios结构描述,定义结构体
    memset(&options, 0x00, sizeof(options));
    //memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值， 这个函数通常为新申请的内存做初始化工作
       
    //使用函数tcgetattr和tcsetattr可以获取和设置串口termios结构属性。
    if (0 != tcgetattr(fd, &options)) { //获得串口属性
         printf("%s error\n", __FUNCTION__);
         return -1;
    }
    tcflush(fd, TCIOFLUSH);//刷新输入输出缓冲区
    //设置波特率
    cfsetispeed(&options, B115200);//设置输入速度为115200
    cfsetospeed(&options, B115200);//设置输出速度为115200
    
    //设置串口属性，TCSANOW：不等数据传输完毕就立即改变属性
    if (0 != tcsetattr(fd, TCSANOW, &options)) {
         printf("---- tc setattr error\n");
         return -1;
    }
    tcflush(fd, TCIOFLUSH);//刷新输入输出缓冲区
    
    //串口属性配置
    printf("set properties\n");
    memset(&options, 0x00, sizeof(options));
    if (0 != tcgetattr(fd, &options)) { //获得串口属性
        printf("tcgetattr failed-->1\n");
        return -1;
    }
    options.c_cflag |= (CLOCAL | CREAD);//这两个选项使驱动程序启动接收字符装置，同时忽略串口信号线的状态
    options.c_cflag &= ~CSIZE;//先把数据位清零
    options.c_cflag |= CS8;//设置数据位为8位
    options.c_cflag &= ~CSTOPB;//设置停止位为1
    options.c_cflag &= ~PARENB; //设置无校验
    options.c_cflag &= ~CRTSCTS;//不启用 RTS/CTS (硬件) 流控制
    options.c_iflag &= ~(IXON | IXOFF | IXANY); //禁用软件流控制
    options.c_iflag &= IGNCR;//忽略CR
    options.c_oflag &= ~OPOST; // 设置输出标志：不执行输出处理
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//设置本地标志：不进行回送，关闭规范输入，关闭扩充输入字符处理，关闭终端产生的信号
    //如果有数据可用，则read最多返回所要求的字节数，如果无数据可用，则read立即返回0
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;
          
    tcflush(fd, TCIFLUSH);//刷新输入缓冲区
    if (0 != tcsetattr(fd, TCSANOW, &options)) {
        printf("tcgetattr failed-->2\n");
        return -1;
    }
    
    printf("loand...\n");
    printf("write and read...\n");
  
    //================================
    
    char buff[1024];
    char readBuff[1024];
    size_t readLengh=1024;
    ssize_t w_ok,r_ok;
        while(1) {
            printf("Please enter the command or press q to exit:\n");
    
            scanf("%s",buff);
            char *sendBuff=buff;
            
            //check input str=='q' or 'Q',if true exit
            if ((strlen(buff) == 1) && (buff[0] == 'q'||buff[0] == 'Q')){
                 printf("Exit!\n");
                 break;
            }
         
           int flag=0;
           while(flag< 10) {
               //写数据
               writedata(fd,sendBuff);
               flag++;
               sleep(2);
               //读数据
               r_ok = read(fd,readBuff,readLengh);
               printf("r_ok %zd\n",r_ok);
               //r读取数据失败，继续读取
               if (r_ok>0 ){
                   printf("Success!\n");
                   printf("read data:%s\n", readBuff);
                   break;
               }
           }
        
        }

    return 0;
}
